package service

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"choujiang/common/db"
	"choujiang/common/models"
	"choujiang/common/utils"
	"net/http"
	"time"
	"encoding/base64"
)

const (
	ExpirationTime   = 3600 * 24 * 7
	SessionKeyPrefix = "BoxSession"
	DAILY_BONUS_KEY  = "BoxKey::leyouboxdailybonus"
)

type MiniLoginUserInfo struct {
	OpenId     string `json:"openid"`
	SessionKey string `json:"session_key"`
	UnionID    string `json:"unionid"`
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
}

type newUserInfo struct {
	OpenId    string    `json:"openId"`    // 名字
	NickName  string    `json:"nickName"`  // 名字
	Gender    int       `json:"gender"`    // 性别
	Language  string    `json:"language"`  // 语言
	City      string    `json:"city"`      // 城市
	Province  string    `json:"province"`  // 省份
	Country   string    `json:"country"`   // 国家
	AvatarURL string    `json:"avatarUrl"` // 头像
	UnionID   string    `json:"unionId"`   // id
	Watermark WaterMark `json:"watermark"`
}

type WaterMark struct {
	AppID     string `json:"appid"` // 群组id
	Timestamp int64  `json:"timestamp"`
}

func CodeToUserInfo(code string, entryInfo *model.Entry) (miniLoginUserInfo *MiniLoginUserInfo, err error) {
	url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", entryInfo.AppId, entryInfo.AppSecret, code)
	fmt.Printf("url: %s\n", url)
	res, err := http.Get(url)
	if err != nil {
		err = fmt.Errorf("[CodeToUserInfo]failed to code to session, err: %+v\n", err)
		return
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		err = fmt.Errorf("[CodeToUserInfo]failed to code to session, http.Status: %s", res.Status)
		return
	}

	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	miniLoginUserInfo = new(MiniLoginUserInfo)
	if err = json.Unmarshal(b, miniLoginUserInfo); err != nil {
		err = fmt.Errorf("[CodeToUserInfo]failed to code to session, parse json failed: %s, err :%+v\n", string(b), err)
		return
	}

	if miniLoginUserInfo.ErrCode != 0 {
		err = fmt.Errorf("[CodeToUserInfo]failed to code to session, errmsg: %+v\n", miniLoginUserInfo)
		return
	}
	return
}

func SetUserSessionKey(opendID, gameID, sessionKey string) (err error) {
	key := fmt.Sprintf("%s:%s:%s", SessionKeyPrefix, opendID, gameID)
	fmt.Printf("key :%+v val : %+v\n", key, sessionKey)
	err = db.MainRedisClient.Set(key, sessionKey, ExpirationTime*time.Second).Err()
	fmt.Printf("err :%+v\n", err)
	return err
}

func GetUserSessionKey(opendID, gameID string) (sessionKey string, err error) {
	key := fmt.Sprintf("%s:%s:%s", SessionKeyPrefix, opendID, gameID)
	fmt.Printf("key :%+v\n", key)
	sessionKey, err = db.MainRedisClient.Get(key).Result()
	if err != nil {
		fmt.Printf("err :%+v\n", err)
	}

	return sessionKey, err
}

//func ParseUserInfo(minigameOpenId string, gameId string, encryptedData, iv string, entryInfo *model.Entry) (userInfo *newUserInfo, err error) {
//	sessionKey, err := GetUserSessionKey(minigameOpenId, gameId)
//	fmt.Printf("-----ParseUserInfo minigameOpenId: %s, gameId: %s, encryptedData: %s, iv: %s", minigameOpenId, gameId, encryptedData, iv)
//	if err != nil {
//		fmt.Printf("-----GetUserSessionKey ParseUserInfo err: %s", err)
//		return
//	}
//
//	key, err := base64.StdEncoding.DecodeString(sessionKey)
//	if err != nil {
//		fmt.Printf("-----base64 DecodeString sessionKey err: %s", err)
//		return
//	}
//
//	data, err := base64.StdEncoding.DecodeString(encryptedData)
//	if err != nil {
//		fmt.Printf("-----base64 DecodeString encryptedData err: %s", err)
//		return
//	}
//
//	ivb, err := base64.StdEncoding.DecodeString(iv)
//	if err != nil {
//		fmt.Printf("-----base64 DecodeString iv err: %s", err)
//		return
//	}
//
//	origData, err := utils.AesPkcs7Decrypt(data, key, ivb)
//	if err != nil {
//		fmt.Printf("-----AesPkcs7Decrypt err: %s", err)
//		return
//	}
//
//	userInfo = &newUserInfo{}
//	fmt.Printf("Unmarshal newUserInfo\n")
//	err = json.Unmarshal(origData, userInfo)
//	if err != nil {
//		fmt.Printf("-----Unmarshal origData err: %s", err)
//		return
//	}
//
//	return
//}

func ParseUserInfo(minigameOpenId string, gameId string, encryptedData, iv string, entryInfo *model.Entry, sessionKey string) (userInfo *newUserInfo, err error) {
	//sessionKey, err := GetUserSessionKey(minigameOpenId, gameId)
	//fmt.Printf("-----ParseUserInfo minigameOpenId: %s, gameId: %s, encryptedData: %s, iv: %s", minigameOpenId, gameId, encryptedData, iv)
	//if err != nil {
	//	fmt.Printf("-----GetUserSessionKey ParseUserInfo err: %s", err)
	//	return
	//}
	key, err := base64.StdEncoding.DecodeString(sessionKey)
	if err != nil {
		fmt.Printf("-----base64 DecodeString sessionKey err: %s", err)
		return
	}
	data, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		fmt.Printf("-----base64 DecodeString encryptedData err: %s", err)
		return
	}
	ivb, err := base64.StdEncoding.DecodeString(iv)
	if err != nil {
		fmt.Printf("-----base64 DecodeString iv err: %s", err)
		return
	}
	origData, err := utils.AesPkcs7Decrypt(data, key, ivb)
	if err != nil {
		fmt.Printf("-----AesPkcs7Decrypt err: %s", err)
		return
	}

	userInfo = &newUserInfo{}
	err = json.Unmarshal(origData, &userInfo)
	if err != nil {
		fmt.Printf("-----Unmarshal origData err: %s", err)
		return
	}

	return
}

//判断用户是否领取每日奖励
func GetDailyBonus(user *model.User) bool {
	key := DAILY_BONUS_KEY + utils.TodayUnix()
	v := db.MainRedisClient.Exists(key)
	if v.Val() == 1 {
		sism := db.MainRedisClient.SIsMember(key, user.Id)
		if !sism.Val() {
			go func() {
				receiveDailyBonus(user)
			}()
			return true
		}
	} else {
		go func() {
			receiveDailyBonus(user)
		}()
		return true
	}
	return false
}

//领取每日登陆奖励
func receiveDailyBonus(user *model.User) {
	userExtra := model.GetUserExtraByUid(user.Id)
	if userExtra != nil {
		userExtra.Coupon += 1
		if _, err := userExtra.Update(); err != nil {
			fmt.Printf("-----[receiveDailyBonus] err: %s", err)
		}
		//记录金币来源，抽奖体验奖励3张奖券
		db.Mgo.WriteCoinsLog(user.Id, CONINS_EARN_COLLECT, user.NickName, utils.TodayUnix(), "登陆游戏奖励1券码", 1)
		key := DAILY_BONUS_KEY + utils.TodayUnix()
		db.MainRedisClient.SAdd(key, user.Id)
	}
	return
}
